﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ITProject.Repository.Abstract;
using ITProject.Domain;
using ITProject.WebUI.Models.ProjectUser;
using ITProject.Domain.Entities;
using ITProject.WebUI.Models;
using ITProject.WebUI.Models.ProjectAdmin;

namespace ITProject.WebUI.Controllers
{
    public partial class ProjectUserController : Controller
    { 
        public ProjectUserController(IProjectRepository projectRepo, IUserRepository userRepo, IMessageRepository messageRepo)
        {
            projectRepository = projectRepo;
            userRepository = userRepo;
            messageRepository = messageRepo;
        }

        private IProjectRepository projectRepository;
        private IUserRepository userRepository;
        private IMessageRepository messageRepository;

        [Authorize]
        public virtual ActionResult Index(string projectName)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View((object)projectName);
        }

        #region obsluga forum
        [Authorize]
        public virtual ActionResult Forum(string projectName)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            var project = projectRepository.GetProjectByName(projectName);
            var topics = projectRepository.GetProjectForumTopics(project.Id);
            ForumProjectUserViewModel viewModel = new ForumProjectUserViewModel();
            viewModel.projectID = project.Id;
            viewModel.Topics = new List<ForumTopic>();
            var users = userRepository.GetAllUsers();
            foreach (var item in topics)
            {
                item.autorName = users.Where(x => x.Id == item.AutorId).FirstOrDefault().Login;
                viewModel.Topics.Add(item);
            }
            return View(viewModel);
        }

        [Authorize]
        public virtual ActionResult AddTopic(int projectID)
        {
            string projectName=projectRepository.GetProjectById(projectID).Name;
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);

            return View(new AddTopicProjectUserViewModel());
        }

        [HttpPost]
        public virtual ActionResult AddTopic(AddTopicProjectUserViewModel viewModel)
        {
            string projectName = projectRepository.GetProjectById(viewModel.ProjectID).Name;
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            var user = userRepository.GetUserByLogin(HttpContext.User.Identity.Name);
            var topic = projectRepository.AddForumTopic(viewModel.Topic, user.Id, viewModel.ProjectID);
            projectRepository.AddPost(viewModel.PostContent, user.Id, topic.Id);
            return RedirectToAction(MVC.ProjectUser.ActionNames.ShowTopic, new { topicId = topic.Id, projectID = viewModel.ProjectID});
        }

        public virtual ActionResult ShowTopic(int topicId)
        {
            int projectID = projectRepository.GetTopicById(topicId).ProjectId;
            string projectName = projectRepository.GetProjectById(projectID).Name;
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);

            ShowTopicProjectUserViewModel viewModel = new ShowTopicProjectUserViewModel();
            viewModel.Posts = new List<PostVM>();
            var posts = projectRepository.GetTopicPosts(topicId);
            viewModel.projectID = topicId;
            viewModel.TopicName = projectRepository.GetTopicName(topicId);
            foreach (var item in posts)
            {
                viewModel.Posts.Add(PostVM.ConvertFromEntity(item));
            }
            ShowTopicProjectUserViewModel.AddAutorsNames(viewModel.Posts, userRepository.GetAllUsers().ToList());
            return View(viewModel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="PostContent"></param>
        /// <param name="projectID">id topicu, nie projektu.... nie chcialo mi sie juz zmieniac</param>
        /// <returns></returns>
        [HttpPost]
        public virtual ActionResult AddPost(string PostContent, int projectID)
        {
            var user = userRepository.GetUserByLogin(HttpContext.User.Identity.Name);
            projectRepository.AddPost(PostContent, user.Id, projectID);
            var idpr = projectRepository.GetProjectIDByTopic(projectID);
            return RedirectToAction(MVC.ProjectUser.ActionNames.ShowTopic, new { topicId = projectID, projectID=idpr }); ;
        }

        #endregion

        /// <summary>
        /// Metoda do zabezpieczenia się przed wykonywaniem czynności związanych z dostępem do zasobów projektu przez innego użytkonika niż jego uczestnik.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu.</param>
        /// <returns>Czy użytkownika ma prawo dostępu do panelu.</returns>
        private bool CheckAccess(string projectName)
        {
            if (projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name) == UserRole.NoRole)
                return false;
            return true;
        }

        #region Wymagania funkcjonalne

        /// <summary>
        /// Metoda do wygenerowania dla uczestnikach danych związanych z wymaganiami funkcjonalnymi w projekcie.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu.</param>
        /// <returns>Widok wyświetlający wymagania funkcjonalne w projekcie.</returns>
        [Authorize]
        public virtual ViewResult FunctionalRequirements(string projectName)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            int projectId=projectRepository.GetProjectId(projectName);
            FunctionalRequirement[] requirements = projectRepository.GetProjectFunctionalRequirements(projectId);
            ProjectAdminFunctionalRequirementViewModel[] vmTab = ProjectAdminFunctionalRequirementViewModel.Convert(requirements);
            ViewData["ProjectName"]=projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vmTab);
            
        }

        /// <summary>
        /// Metoda renderuje widok wyświetlający szczegóły pojedynczego wymagania funkcjonalnego.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu.</param>
        /// <param name="requirementId">Identyfikator wymagania.</param>
        /// <returns>Widok ze szczegółami pojedynczego wymagania.</returns>
        [Authorize]
        public virtual ViewResult FunctionalRequirement(string projectName, int requirementId)
        {
            ITProject.Domain.Entities.FunctionalRequirement requirement = projectRepository.GetFunctionalRequirementById(requirementId);
            string author = userRepository.GetUserById(requirement.AuthorId).Login;
            Scenario[] scenarios = projectRepository.GetRequirementScenarios(requirement.Id);
            ProjectUserFunctionalRequirementViewModel vm = ProjectUserFunctionalRequirementViewModel.Convert(requirement, author, scenarios);
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vm);
        }

        #endregion

        #region funkcjonalności

        /// <summary>
        /// Metoda generująca widok featerów przypisanych do uczestnika.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu.</param>
        /// <returns>Widok z listą feature'ór uczestnika.</returns>
        [Authorize]
        public virtual ViewResult MyFeatures(string projectName)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            Project project = projectRepository.GetProjectByName(projectName);
            User user=userRepository.GetUserByLogin(User.Identity.Name);
            Feature[] features = projectRepository.GetUserFeatures(user.Id,project.Id);
            ProjectUserMyFeatureViewModel[] vmTab = ProjectUserMyFeatureViewModel.Convert(features);
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vmTab.OrderBy(x => x.PlannedEndDate));
        }

        /// <summary>
        /// Metoda służy do wyświetlenia szczegłów na temat danej funkcjonalności należącej do użytkownika.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu.</param>
        /// <param name="featureId">Identyfikator funkcjonalności.</param>
        /// <returns>Widok wyświetlający szczegóły funkcjonalności.</returns>
        [Authorize]
        public virtual ViewResult MyFeatureDetails(string projectName, int featureId)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            // sprawdzenie czy dana funckjonalność rzeczywiście należy do zalogowanego usera
            User u=projectRepository.GetFeatureUserByFeatureId(featureId);
            if (u.Login!=User.Identity.Name)
                 throw new Exception("Brak dostępu");

            Feature feature=projectRepository.GetFeatureById(featureId);
            StatusChange[] scTab;
            string[] statusChangeUsersTab;
            projectRepository.GetFeatureStatusChanges(feature,out scTab, out statusChangeUsersTab);
            string releaseName="";
            if (feature.ReleaseId != null)
                releaseName = projectRepository.GetReleaseById((int)feature.ReleaseId).Name;
            ProjectUserMyFeatureDetailsViewModel vm = ProjectUserMyFeatureDetailsViewModel.Convert(feature,scTab,statusChangeUsersTab,releaseName);
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vm);
        }

        /// <summary>
        /// Metoda do zmiany statusu swojej funkcjonalności.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu.</param>
        /// <param name="featureId">Identyfikator funkcjonalności.</param>
        /// <returns>Widok pozwalający zmienić status funkcjonalności.</returns>
        [Authorize]
        public virtual ViewResult ChangeMyFeatureStatus(string projectName, int featureId)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            // sprawdzenie czy dana funckjonalność rzeczywiście należy do zalogowanego usera
            User u = projectRepository.GetFeatureUserByFeatureId(featureId);
            if (u.Login != User.Identity.Name)
                throw new Exception("Brak dostępu");

            Feature feature = projectRepository.GetFeatureById(featureId);
            ProjectUserChangeMyFeatureStatusViewModel vm = ProjectUserChangeMyFeatureStatusViewModel.Convert(feature, projectName);
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vm);
        }

        /// <summary>
        /// Metoda typu HttpPost przyjmująca formularz zmiany statusu funkcjonalności.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="vm">Obiekt modelu widokowego zmiany funkcjonalności.</param>
        /// <returns>Akcja związana z wyświetleniem funkcjonalności uczestnika.</returns>
        [Authorize]
        [HttpPost]
        public virtual ActionResult ChangeMyFeatureStatus(ProjectUserChangeMyFeatureStatusViewModel vm)
        {
            string projectName = vm.ProjectName;
            int featureId = vm.FeatureId;
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            // sprawdzenie czy dana funckjonalność rzeczywiście należy do zalogowanego usera
            User u = projectRepository.GetFeatureUserByFeatureId(featureId);
            if (u.Login != User.Identity.Name)
                throw new Exception("Brak dostępu");

            Feature feature = projectRepository.GetFeatureById(featureId);
            // sprawdzenie czy zmiana nie zmienia z tego samego w to samo
            if (feature.Status != (byte)StatusName.ConvertFromString(vm.ReturnStatus))
            {
                StatusChange sc = ProjectUserChangeMyFeatureStatusViewModel.Convert(vm, feature.Status, u.Id);
                projectRepository.ChangeFeatureStatus(feature, sc);
            } 
            return RedirectToAction(MVC.ProjectUser.ActionNames.MyFeatures, new { projectName = projectName });
        }

        #endregion

        #region zadania

        public virtual ViewResult MyTasks(string projectName)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            User user = userRepository.GetUserByLogin(User.Identity.Name);
            Project project=projectRepository.GetProjectByName(projectName);
            Task[] tasks = projectRepository.GetUserTasks(user.Id,project.Id);
            
            ProjectUserMyTaskViewModel[] vmTab = ProjectUserMyTaskViewModel.Convert(tasks);
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vmTab.OrderBy(x => x.PlannedEndDate));
        }

        /// <summary>
        /// Metoda służy do wyświetlenia szczegłów na temat danej funkcjonalności należącej do użytkownika.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu.</param>
        /// <param name="featureId">Identyfikator funkcjonalności.</param>
        /// <returns>Widok wyświetlający szczegóły funkcjonalności.</returns>
        [Authorize]
        public virtual ViewResult MyTaskDetails(string projectName, int taskId)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            Task task = projectRepository.GetTaskById(taskId);
            // sprawdzenie czy dana funckjonalność rzeczywiście należy do zalogowanego usera
            User u = userRepository.GetUserById(task.UserId);
            if (u.Login != User.Identity.Name)
                throw new Exception("Brak dostępu");

            StatusChange[] scTab;
            string[] statusChangeUsersTab;
            projectRepository.GetTaskStatusChanges(task, out scTab, out statusChangeUsersTab);
            string featureName = "";
            if (task.FeatureId != null)
                featureName = projectRepository.GetFeatureById((int)task.FeatureId).Name;
            ProjectUserMyTaskDetailsViewModel vm = ProjectUserMyTaskDetailsViewModel.Convert(task, scTab, statusChangeUsersTab, featureName);
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vm);
        }

        /// <summary>
        /// Metoda do zmiany statusu swojego zadania.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu.</param>
        /// <param name="featureId">Identyfikator zadania.</param>
        /// <returns>Widok pozwalający zmienić status zadania.</returns>
        [Authorize]
        public virtual ViewResult ChangeMyTaskStatus(string projectName, int taskId)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            // sprawdzenie czy dana funckjonalność rzeczywiście należy do zalogowanego usera
            Task task = projectRepository.GetTaskById(taskId);
            User u = userRepository.GetUserById(task.UserId);
            if (u.Login != User.Identity.Name)
                throw new Exception("Brak dostępu");

            ProjectUserChangeMyTaskStatusViewModel vm = ProjectUserChangeMyTaskStatusViewModel.Convert(task, projectName);
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vm);
        }

        /// <summary>
        /// Metoda typu HttpPost przyjmująca formularz zmiany statusu zadania.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="vm">Obiekt modelu widokowego zmiany statusu zadania.</param>
        /// <returns>Akcja związana z wyświetleniem zadań uczestnika.</returns>
        [Authorize]
        [HttpPost]
        public virtual ActionResult ChangeMyTaskStatus(ProjectUserChangeMyTaskStatusViewModel vm)
        {
            string projectName = vm.ProjectName;
            Task task = projectRepository.GetTaskById(vm.TaskId);
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            // sprawdzenie czy dana funckjonalność rzeczywiście należy do zalogowanego usera
            User u = userRepository.GetUserById(task.UserId);
            if (u.Login != User.Identity.Name)
                throw new Exception("Brak dostępu");

            // sprawdzenie czy zmiana nie zmienia z tego samego w to samo
            if (task.Status != (byte)StatusName.ConvertFromString(vm.ReturnStatus))
            {
                StatusChange sc = ProjectUserChangeMyTaskStatusViewModel.Convert(vm, task.Status, u.Id);
                projectRepository.ChangeTaskStatus(task, sc);
            }
            return RedirectToAction(MVC.ProjectUser.ActionNames.MyTasks, new { projectName = projectName });
        }

        #endregion

        #region repozytorium SVN

        [Authorize]
        public virtual ActionResult Repository(string projectName)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            Project project = projectRepository.GetProjectByName(projectName);
            var history = userRepository.GetRepositoryEntry(project.Id, User.Identity.Name);
            ListRPUViewModel vm = new ListRPUViewModel();
            foreach (var item in history)
            {
                vm.repositorEntries.Add(RepositoryProjectUserViewModel.Convert(item));
            }
            return View(vm);
        }

        #endregion

        #region calender
        public virtual ActionResult ProjectCalendar(string projectName)
        {
            if (!CheckAccess(projectName))
                throw new Exception("Brak dostępu");      
            Team[] teams = projectRepository.GetProjectTeams(projectName).ToArray();
            Project project=projectRepository.GetProjectByName(projectName);
            User[] users = userRepository.GetAllUsers().ToArray();
            Task[] tasks=projectRepository.GetProjectTasks(project.Id);
            Feature[] feature=projectRepository.GetProjectFeatures(project.Id);
            Release[] release=projectRepository.GetProjectReleases(project.Id);
            
            ProjectUserCalenderViewModel vm = ProjectUserCalenderViewModel.ConvertToVM(feature, tasks, release, users,teams,projectRepository,project.Id);
            vm.projectName = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);

            return View(vm);
        }
        
        #endregion
    }
}
